package paa.simulator.grafo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import paa.simulator.grafo.PessoaPool.Pessoa;
import paa.simulator.grafo.VideoPool.Video;
import paa.simulator.grafo.simple.UndirectedSimpleGraph;

public class GraphFromData {

	private static final Uploads EMPTY_UPLOADS = new Uploads(new HashSet<Video>());
	private static final Subscriptions EMPTY_SUBSCRIPTIONS = new Subscriptions(new HashSet<Pessoa>());
	private static final Favoritos EMPTY_FAVORITOS = new Favoritos(new HashSet<Video>());
	private static final String EMPTY_NAME = "";
	private static final String LIST_DELIMITERS = "\\[|\\]";
	private static final String LIST_SPLITER = ",\\s";
	private static final String VID_TAG_SPLITER = "\\s:\\s";
	private static final String HTTP_GDATA_YOUTUBE_COM_FEEDS_API_VIDEOS = "http://gdata.youtube.com/feeds/api/videos/";

	public static UndirectedSimpleGraph<PessoaVertex> createGraph(File[] subdirs, double threshold, GraphBuilder.Type type) throws Exception {
		List<Pessoa> pessoas = new ArrayList<Pessoa>();
		
		Pattern userNamePattern = Pattern.compile("#user:\\s(.*)");
		Pattern uploadsPattern = Pattern.compile("#uploads:\\s\\[(.*),\\s\\]");
		Pattern favoritesPattern = Pattern.compile("#favorites:\\s\\[(.*),\\s\\]");
		Pattern subscriptionsPattern = Pattern.compile("#subscriptions:\\s\\[(.*),\\s\\]");
		
		PossibleRelations pr = new PossibleRelations();
		
		for (File subdir : subdirs) {

			Favoritos fav = EMPTY_FAVORITOS;
			Subscriptions subs = EMPTY_SUBSCRIPTIONS;
			Uploads ups = EMPTY_UPLOADS;
			Pessoa pessoa = null;
			
			for (File file : subdir.listFiles()) {
				BufferedReader reader = null;
				try {
					reader = new BufferedReader(new FileReader(file));
					String line;
					while((line = reader.readLine()) != null) {
						
						Matcher userNameMatcher = userNamePattern.matcher(line);
						Matcher uploadsMatcher = uploadsPattern.matcher(line);
						Matcher favoritesMatcher = favoritesPattern.matcher(line);
						Matcher subscriptionsMatcher = subscriptionsPattern.matcher(line);
						
						if (userNameMatcher.matches()) {
							pessoa = PessoaPool.getInstance().overwritePessoa(userNameMatcher.group(1).hashCode(), EMPTY_FAVORITOS, EMPTY_SUBSCRIPTIONS, EMPTY_UPLOADS);
						} else if ((type == GraphBuilder.Type.COMMON_FAVORITE_TAGS || type == GraphBuilder.Type.COMMON_FAVORITE_VIDEO) && favoritesMatcher.matches()) {
							String group = favoritesMatcher.group(1);
							String[] strings = group.split(HTTP_GDATA_YOUTUBE_COM_FEEDS_API_VIDEOS);
							
							HashSet<Video> favorites = new HashSet<Video>();
							extractVideos(strings, favorites);
							
							for (Video v : favorites) {
								if (type == GraphBuilder.Type.COMMON_FAVORITE_VIDEO) {
									pr.addPossibleVideoRelation(v, pessoa);
								} else {
									for(Integer tag : v.getTags()) {
										pr.addPossibleTagRelation(tag, pessoa);
									}
								}
							}
							
							fav = new Favoritos(favorites);
						} else if (type == GraphBuilder.Type.COMMON_SUBSCRIPTIONS && subscriptionsMatcher.matches()) {
							String group = subscriptionsMatcher.group(1);
							String[] strings = group.split(LIST_SPLITER);
							
							Set<Pessoa> set = new HashSet<Pessoa>();
							for (String s : strings) {
								int userID = s.hashCode();
								Pessoa subscription = PessoaPool.getInstance().getPessoa(userID);
								
								if (subscription == null) {
									subscription = PessoaPool.getInstance().putPessoa(userID, EMPTY_FAVORITOS, EMPTY_SUBSCRIPTIONS, EMPTY_UPLOADS);
								}
								
								pr.addPossibleSubscriptionRelation(subscription, pessoa);
								set.add(subscription);
							}
							
							subs = new Subscriptions(set);
						} else if (false && uploadsMatcher.matches()) { //o and false é pra nao perder o codigo =D
							String group = uploadsMatcher.group(1);
							String[] strings = group.split(HTTP_GDATA_YOUTUBE_COM_FEEDS_API_VIDEOS);
						
							HashSet<Video> uploads = new HashSet<Video>();
							extractVideos(strings, uploads);
						
							ups = new Uploads(uploads);
						}
					}
					
					reader.close();
					pessoa = PessoaPool.getInstance().overwritePessoa(pessoa.getID(), fav, subs, ups);
					pessoas.add(pessoa);
				} finally {						
					if (reader != null) {
						reader.close();
					}
				}
			}
		}
		
		UndirectedSimpleGraph<PessoaVertex> graph = GraphBuilder.criaGrafo(pessoas, threshold, pr, type);
		pr.clear();
		
		return graph;
	}

	private static void extractVideos(String[] strings, HashSet<Video> storage) {
		for (String video : strings) {
			if (video.length() != 0) {
				String[] videoTags = video.split(VID_TAG_SPLITER);
				String videoName = videoTags[0];
				int videoID = videoName.hashCode();
				
				Video instance = VideoPool.getInstance().getVideo(videoID);
				if (instance == null) {
					String tagsLine = videoTags[1];
					String[] tagTokens = tagsLine.split(LIST_SPLITER);
					
					HashSet<Integer> list = new HashSet<Integer>();
					for (String tag : tagTokens) {
						tag = tag.replaceAll(LIST_DELIMITERS, EMPTY_NAME).toLowerCase();
						list.add(tag.hashCode());
					}
					
					instance = VideoPool.getInstance().putVideo(videoID, list);
				}
				
				storage.add(instance);
			}
		}
	}
}